package com.example.websocket.controller;

import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@ServerEndpoint("/chat/{username}")
@Component
public class ChatController {
    // 静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

    // concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<ChatController> webSocketSet = new CopyOnWriteArraySet<>();

    // 与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;

    // 接收用户名
    private String username = "";

    // 用于存所有的用户信息
    private static ConcurrentHashMap<String, Session> map = new ConcurrentHashMap<>();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("username") String username) {
        this.session = session;
        webSocketSet.add(this);     // 加入set中
        map.put(username, session);
        this.username = username;
        addOnlineCount();           // 在线数加1
        System.out.println("有新连接加入！当前在线人数为" + getOnlineCount());
        try {
            sendMessage("连接成功");
            // 广播通知有新用户加入
            broadcast(username + "加入了聊天室");
        } catch (IOException e) {
            System.out.println("IO异常");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  // 从set中删除
        map.remove(username);
        subOnlineCount();           // 在线数减1
        System.out.println("有一连接关闭！当前在线人数为" + getOnlineCount());
        // 广播通知用户离开
        try {
            broadcast(username + "离开了聊天室");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("来自客户端的消息:" + username + ":" + message);

        // 解析消息格式，如果是私聊格式 @用户名:消息内容
        if (message.startsWith("@")) {
            int index = message.indexOf(":");
            if (index != -1) {
                String targetUser = message.substring(1, index);
                String content = message.substring(index + 1);
                try {
                    sendToUser(targetUser, username + "悄悄对你说：" + content);
                    // 给自己也发送一份
                    sendMessage("你悄悄对" + targetUser + "说：" + content);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return;
            }
        }

        // 群发消息
        for (ChatController item : webSocketSet) {
            try {
                item.sendMessage(username + "：" + message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("发生错误");
        error.printStackTrace();
    }

    /**
     * 向客户端发送消息
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 广播消息
     */
    public static void broadcast(String message) throws IOException {
        for (ChatController item : webSocketSet) {
            item.sendMessage(message);
        }
    }

    /**
     * 发送消息给指定用户
     */
    public static void sendToUser(String username, String message) throws IOException {
        Session session = map.get(username);
        if (session != null) {
            session.getBasicRemote().sendText(message);
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        ChatController.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        ChatController.onlineCount--;
    }
}
